package com.jonosoft.photocast.viewer.web.client;

import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;

/**
 * @author Jon Kelling - {@link jonkelling@gmail.com}
 */
public abstract class DeferredCommandSequence implements Command {

	private int numberOfCallsPerIteration = 0;
	private int maxCallsPerSequence = 0;
	private int currentIndex = 0;

	public DeferredCommandSequence(int numberOfCallsPerIteration, int maxCallsPerSequence) {
		this.numberOfCallsPerIteration = numberOfCallsPerIteration;
		this.maxCallsPerSequence = maxCallsPerSequence;
		this.currentIndex = 0;
	}

	public DeferredCommandSequence(int maxCallPerSequence) {
		this(1, maxCallPerSequence);
	}

	public void startSequence() {
		DeferredCommand.add(this);
		currentIndex = 0;
	}

	public void endSequence() {
		currentIndex = maxCallsPerSequence;
	}

	/**
	 * If we're not at the end of the sequence, make two calls:
	 * onIterationStart() once and onCall() multiple times as defined by
	 * numberOfCallsPerIteration
	 *
	 * @see com.google.gwt.user.client.Command#execute()
	 */
	public final void execute() {
		if (!isEndOfSequence()) {
			int last = Math.min(currentIndex + numberOfCallsPerIteration, maxCallsPerSequence);

			onIterationStart(currentIndex);

			for (; currentIndex < last; currentIndex++)
				onCall(currentIndex);

			if (last < maxCallsPerSequence)
				DeferredCommand.add(this);
		}
	}

	public boolean isEndOfSequence() {
		return (currentIndex >= maxCallsPerSequence);
	}

	public int getCurrentNumberInSequence() {
		return currentIndex;
	}

	public int getNumberOfCallsPerIteration() {
		return numberOfCallsPerIteration;
	}

	public int getMaxCallsPerSequence() {
		return maxCallsPerSequence;
	}

	public void setNumberOfCallsPerIteration(int numberOfCallsPerIteration) {
		this.numberOfCallsPerIteration = numberOfCallsPerIteration;
	}

	public void setMaxCallsPerSequence(int maxCallsPerSequence) {
		this.maxCallsPerSequence = maxCallsPerSequence;
	}

	/**
	 * This gets called each time a {@link Command} executes.
	 *
	 * @param numberInSequence
	 */
	protected abstract void onIterationStart(int numberInSequence);

	/**
	 * This gets called multiple times per iteration ({@link Command#execute()})
	 * as defined by numberOfCallsPerIteration
	 *
	 * @param numberInSequence
	 */
	protected abstract void onCall(int numberInSequence);

}
